package tool

import java.awt.Color
import java.io.{File, FileFilter, FileInputStream, FileOutputStream, FilenameFilter}
import java.net.URLEncoder
import java.nio.file.Files
import java.text.SimpleDateFormat
import java.util.concurrent.ForkJoinPool

import javax.inject.Inject
import org.joda.time.DateTime
import utils.{CommandExecutor, Utils}
import dao._
import models.Tables.{KegginfoRow, MissionRow, UserKegginfoRow}
import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.StringUtils
import org.apache.poi.ss.usermodel.{Cell, DateUtil, FillPatternType, IndexedColors}
import org.apache.poi.xssf.usermodel.{XSSFColor, XSSFWorkbook}
import play.api.libs.Files.TemporaryFile
import play.api.mvc.{MultipartFormData, Request, RequestHeader}
import shared.VarTool
import tool.Pojo._

import scala.collection.JavaConverters._
import scala.collection.mutable
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import implicits.Implicits._
import tool.Tool.{linuxTestDir, playPath, windowsTestDir}

/**
 * Created by yz on 2018/9/19
 */
class Tool @Inject()(modeDao: ModeDao, keggInfoDao: KeggInfoDao) {

  def producePairsInfoFile(dataFile: File, workspaceDir: File, species: String) = {
    val parent = new File(Utils.dataDir, "species")
    val file = new File(parent, s"${species}.txt")
    val set = file.lines.drop(1).flatMapSetByColumns { columns =>
      val subs = columns(3).split(" + ")
      val pros = columns(4).split(" + ")
      subs.flatMap { sub =>
        pros.map { pro =>
          s"${pro}/${sub}"
        }
      }.toSet
    }
    val keggInfoFile = new File(workspaceDir, "keggInfo.txt")
    val headers = keggInfoFile.txtLines.head
    val keggIds = keggInfoFile.lines.filterLineSize(_ >= 5).mapOtherByColumns { columns =>
      val map = headers.zip(columns).toMap
      map("KEGG")
    }
    val keggSets = keggIds.combinations(2).flatMap { keggIds =>
      Set(s"${keggIds.head}/${keggIds.last}", s"${keggIds.last}/${keggIds.head}")
    }.toSet
    val finalSet = keggSets.intersect(set)
    finalSet.toList.toFile(new File(workspaceDir, "pairInfo.txt"))

  }

}

object Tool extends ProjectTool with ProjectFileTool {

  val playPath = new File("../").getAbsolutePath
  val windowsTestDir = new File("C:\\temp")
  val linuxTestDir = new File(playPath, "workspace")
  val testDir = if (windowsTestDir.exists()) windowsTestDir else linuxTestDir
  val smallBaseFile = new File(Utils.rPath, "base.R")
  val databaseDir = new File(Utils.dataDir, "libs")

  def getSteps(testSteps: List[MyStep])(implicit modeDao: ModeDao) = if (isTestMode) {
    testSteps
  } else {
    Tool.allSteps
  }

  def deleteDirectory(direcotry: File)(implicit modeDao: ModeDao) = {
    if (!isTestMode) Utils.deleteDirectory(direcotry)
  }

  def isTestMode(implicit modeDao: ModeDao) = {
    val mode = Utils.execFuture(modeDao.select)
    if (mode.test == "t") true else false
  }

  def createTempDirectory(prefix: String)(implicit modeDao: ModeDao) = {
    if (isTestMode) Tool.testDir else Files.createTempDirectory(prefix).toFile
  }

  def urlEncode(url: String) = {
    URLEncoder.encode(url, "UTF-8")
  }

  def getContentDisposition(url: String) = {
    val encodeUrl = Tool.urlEncode(url)
    s"attachment; filename*=utf-8''${encodeUrl}"
  }

  def fdrDeal(configData: ConfigData) = {
    val fdr = configData.diffMethod.fdr
    val kwFdr = configData.diffMethod.kwFdr
    val corFdr =  configData.cor.fdr
    val corCopy = configData.cor.copy(fdr = corFdr)
    val diffMethodCopy = configData.diffMethod.copy(fdr = fdr, kwFdr = kwFdr)
    configData.copy(cor = corCopy, diffMethod = diffMethodCopy)
  }

  def produceKeggInfoFile(dataFile: File, workspaceDir: File)(implicit dao: MyDao) = {
    val json = Utils.getJsonByConfigFile(workspaceDir)
    val otherConfigData = FormTool.otherConfigForm.bind(json).get
    val map = dataFile.csvLines.drop(1).map { columns =>
      val name = columns(0)
      val cleanName = Tool.cleanName(name)
      (cleanName, name)
    }.toMap
    val names = map.keys.toList
    val userKeggInfos = if (otherConfigData.dbId == 0) {
      Tool.selectKeggInfos(names)
    } else {
      Tool.selectUserKeggInfos(names, otherConfigData.dbId)
    }
    val hmdbKeggInfos = Tool.selectHmdbKeggInfos(names)
    val keggInfos = (userKeggInfos ++ hmdbKeggInfos).distinctByKeepHead(_.cleanName)

    def ts2File = {
      implicit val sep = "\t"
      val headers = List("Class", "Raw_Metabolite", "Metabolite", "HMDB", "KEGG")
      val newLines = keggInfos.map { case keggInfo =>
        val accession = keggInfo.accession
        val name = keggInfo.cleanName
        val orignalName = map.getOrElse(name, "")
        val finalName = keggInfo.finalName
        val trueFinalName = if (finalName.isBlank) orignalName else finalName
        List(keggInfo.superclass, orignalName, trueFinalName, keggInfo.accession, keggInfo.keggid)
      }.distinct

      val tmpLines = newLines.distinctByKeepHead(_ (1))
      val finalLines = tmpLines.groupBy(_ (2)).mapValues { lines =>
        lines.zipWithIndex.map { case (columns, i) =>
          if (i == 0) columns else columns.updated(2, s"${columns(2)}_${i}")
        }
      }.values.flatten.toList

      (headers :: finalLines).toTxtFile(new File(workspaceDir, "keggInfo.txt"))
    }

    ts2File

  }

  def selectKeggInfos(names: Seq[String])(implicit dao: MyDao) = {
    case class MyKegginfoRow(index: String, name: String, strandardName: String, accession: String, keggid: String,
                             superclass: String, cleanName: String, strandardCleanName: String)
    val f = dao.keggInfoDao.selectAll.map { tmpKeggInfos =>
      val keggInfos = tmpKeggInfos.map { x =>
        MyKegginfoRow(index = x.index, name = x.name, strandardName = x.strandardName,
          accession = x.accession, keggid = x.keggid, superclass = x.superclass, cleanName = Tool.cleanName(x.name),
          strandardCleanName = Tool.cleanName(x.strandardName))
      }
      val nameKeggInfos = keggInfos.distinctByKeepHead(_.cleanName)
      val nameKeggInfoMap = nameKeggInfos.map { row =>
        (row.cleanName, row)
      }.toMap
      val standradNameKeggInfos = keggInfos.distinctByKeepHead(_.strandardCleanName)
      val standradNameKeggInfoMap = standradNameKeggInfos.map { row =>
        (row.strandardCleanName, row)
      }.toMap
      val rows = names.map { name =>
        if (nameKeggInfoMap.isDefinedAt(name)) {
          val row = nameKeggInfoMap(name)
          KeggInfoData(row.strandardName, row.accession, row.keggid, row.superclass, row.cleanName)
        } else if (standradNameKeggInfoMap.isDefinedAt(name)) {
          val row = standradNameKeggInfoMap(name)
          KeggInfoData("", row.accession, row.keggid, row.superclass, row.strandardCleanName)
        } else KeggInfoData("", "", "", "", "")
      }.filter(_.cleanName.nonEmpty)
      rows
    }
    Utils.execFuture(f)
  }

  def selectUserKeggInfos(names: Seq[String], dbId: Int)(implicit dao: MyDao) = {
    case class MyUserKegginfoRow(metaboId: Int, index: String, name: String, strandardName: String, accession: String,
                                 keggid: String, superclass: String, cleanName: String, strandardCleanName: String)
    val f = dao.userKeggInfoDao.selectAll(dbId).map { tmpkeggInfos =>
      val keggInfos = tmpkeggInfos.map { x =>
        MyUserKegginfoRow(metaboId = x.metaboId, index = x.index, name = x.name, strandardName = x.strandardName,
          accession = x.accession, keggid = x.keggid, superclass = x.superclass, cleanName = Tool.cleanName(x.name),
          strandardCleanName = Tool.cleanName(x.strandardName))
      }
      val nameKeggInfos = keggInfos.distinctByKeepHead { x =>
        x.cleanName
      }
      val nameKeggInfoMap = nameKeggInfos.map { row =>
        (row.cleanName, row)
      }.toMap
      val standradNameKeggInfos = keggInfos.distinctByKeepHead(_.strandardCleanName)
      val standradNameKeggInfoMap = standradNameKeggInfos.map { row =>
        (row.strandardCleanName, row)
      }.toMap
      val rows = names.map { name =>
        if (nameKeggInfoMap.isDefinedAt(name)) {
          val row = nameKeggInfoMap(name)
          KeggInfoData(row.strandardName, row.accession, row.keggid, row.superclass, row.cleanName)
        } else if (standradNameKeggInfoMap.isDefinedAt(name)) {
          val row = standradNameKeggInfoMap(name)
          KeggInfoData("", row.accession, row.keggid, row.superclass, row.strandardCleanName)
        } else KeggInfoData("", "", "", "", "")
      }.filter(_.cleanName.nonEmpty)
      rows
    }
    Utils.execFuture(f)
  }

  def selectHmdbKeggInfos(names: Seq[String])(implicit dao: MyDao) = {
    val f = dao.hmdbKeggInfoDao.selectAll(names).zip(dao.hmdbOtherNameKeggDao.selectAll(names)).
      flatMap { case (keggInfos, otherNameKeggs) =>
        val keggInfoMap = keggInfos.map { row =>
          (row.cleanName, row)
        }.toMap
        val otherMap = otherNameKeggs.map { row =>
          (row.cleanName, row)
        }.toMap
        val idMap = names.map { name =>
          if (keggInfoMap.isDefinedAt(name)) {
            (name, name)
          } else if (otherMap.isDefinedAt(name)) {
            (Tool.cleanName(otherMap(name).name), name)
          } else ("", "")
        }.filter(_._1.nonEmpty).toMap
        dao.hmdbKeggInfoDao.selectAll(idMap.keys.toList).map { keggInfos =>
          keggInfos.map { row =>
            val cleanName = idMap(row.cleanName)
            KeggInfoData("", row.accession, row.keggid, row.superclass, cleanName)
          }
        }
      }
    Utils.execFuture(f)
  }


  def getDataDir(dataDir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val dataCsvFileOp = Tool.fileMoveDirOp("dataCsvFile", dataDir)
    val dataXlsxFileOp = Tool.fileMoveDirOp("dataXlsxFile", dataDir)
    val dataFile = if (dataCsvFileOp.isDefined) {
      dataCsvFileOp.get
    } else {
      val tmpDataFile = dataXlsxFileOp.get
      val destFile = new File(tmpDataFile.getParent, s"${tmpDataFile.namePrefix}.csv")
      tmpDataFile.xlsxLines.toFile(destFile)
      destFile
    }

    val groupFile = Tool.fileMoveDir("groupFile", dataDir)
    val compareFile = Tool.fileMoveDir("compareFile", dataDir)
    val sampleColorFile = Tool.fileMoveDirOp("sampleColorFile", dataDir)
    val tmpCorDir = Tool.createAndReturnDir(dataDir, "cor_extra_data")
    Tool.filesMove("extraDataFile", tmpCorDir)
    val confounderFile = Tool.fileMoveDirOp("confounderFile", dataDir)
    MyDataDir(dataDir, dataFile, groupFile, compareFile, sampleColorFile, tmpCorDir,
      confounderFile)
  }

  val allSteps: List[MyStep] = List(Step0, StepPca, StepBasic, StepPlsda, StepOplsda(), StepUni(), StepPotential(),
    StepCor, StepPathway(), StepDignose)

  val corExtraDataDirName = "cor_extra_data"
  val confounderFileName = "confounder.csv"

  def produceConfigFile(configData: ConfigData, workspaceDir: File) = {
    val newLines = Utils.getLinesByT(configData)
    val configFile = new File(workspaceDir, "config.txt")
    newLines.toFile(configFile)
    configFile
  }

  def getConfigData(configFile: File) = {
    val map = configFile.csvLines.map { columns =>
      (columns(0) -> columns(1))
    }.toMap
    val libTypes = map("pathway.libTypes").split(";")

    val corData = CorData(map("cor.isSelfCorExec"), map("cor.isCorExec"), map("cor.isParCorExec"), map("cor.coe"), map("cor.p"), map("cor.fdr"))
    val diffMethodData = DiffMethodData(map("diffMethod.method"), map("diffMethod.fcMethod"), map("diffMethod.mulMethod"), map("diffMethod.pValue"),
      map("diffMethod.fdr"), map("diffMethod.log2FC"), map("diffMethod.kwP"), map("diffMethod.kwFdr"))
    val reportHomeMap = Tool.getReportHomeMap(map)
    val reportHome = Utils.to[ReportHomeData].from(reportHomeMap).get
    val pathwayData = PathwayData(map("pathway.isIPathExec"), map("pathway.isEnrichExec"), libTypes,
      map("pathway.isPathwayExec"), map("pathway.method"), map("pathway.nodeImp"))
    val oplsData = OplsdaData(map(VarTool.vipName), map(VarTool.q2YName), map(VarTool.q2YBName))
    val preDealData = PreDealData(map("preDeal.replaceMethod"), map("preDeal.knn"), map("preDeal.min"))
    ConfigData(map("threadNum").toInt, map("isInter"), map("rfTop"), map("svmTop"), corData, pathwayData,
      map("species"), map("isSmp"), map("anaKind"), map("diagnoseIsExec"), map("coef"),
      map("isLoess"), map("isNormal"), preDealData, diffMethodData, oplsData, map("borutaAfterTopN"), map("execCv"),
      map("seed"),map("k"), reportHome,
      map.get("colorSolution")
    )
  }

  def produceInConfigFile(configData: ConfigData, columns: List[String], workspaceDir: File) = {
    val outerConfigFile = new File(workspaceDir.getParentFile.getParentFile, "config.txt")
    val configFile = new File(workspaceDir, "config.csv")
    val isMul = Tool.isMulti(columns(0))
    val isPaired = if (isMul || (columns(1) != "Y")) {
      "F"
    } else "T"
    val lines = outerConfigFile.csvLines
    val newLine = List("isPaired", isPaired)
    val newLines = lines :+ newLine
    newLines.toFile(configFile)
    configFile
  }


  def fileMove(fieldName: String, file: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    if (tempFile.ref.path.toFile.length() > 0) {
      tempFile.ref.moveTo(file, replace = true)
    }
  }

  def fileMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirOp(fieldName, dir).get
  }

  def fileMoveDirOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    request.body.file(fieldName).flatMap { tempFile =>
      if (tempFile.ref.path.toFile.length() > 0) {
        val destFile = new File(dir, tempFile.filename)
        tempFile.ref.moveTo(destFile, replace = true)
        Some(destFile)
      } else None
    }

  }

  def filesMove(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    request.body.files.filter(_.key == fieldName).foreach { tmpFile =>
      if (tmpFile.ref.path.toFile.length() > 0) {
        val fileName = tmpFile.filename
        val corFile = new File(dir, fileName)
        tmpFile.ref.moveTo(corFile, replace = true)
      }
    }
  }

  def getDataFile(workspaceDir: File, outDir: File, configData: ConfigData) = {
    val outFile = new File(outDir, "AllMet.csv")
    val fileName = configData.anaKind match {
      case "allMet" => "04_AllMet.csv"
      case "allWithRatio" => "06_AllMet_and_Ratio.csv"
      case "onlyRatio" => "05_Ratio_Raw.csv"
    }
    val srcFile = new File(workspaceDir, fileName)
    FileUtils.copyFile(srcFile, outFile)
    outFile
  }

  def stepPre(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "data_header_deal.R").unixPath} --i ${myInput.rawDataFile.unixPath} --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "data_filter.R").unixPath} --i ${myInput.rawDataFile.unixPath} --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "data_replace.R").unixPath}  --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "loess.R").unixPath}  --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "normal.R").unixPath} --t normal --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_data_file.R").unixPath} --i ${myInput.rawDataFile.unixPath} --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_data_file_with_pathway.R").unixPath} --i ${myInput.rawDataFile.unixPath} --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath} --d ${Tool.databaseDir.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_data_file_with_raw_metabolite.R").unixPath} --i ${myInput.rawDataFile.unixPath} --g ${myInput.groupFile.unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_pairs_data.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_sample_color.R").unixPath} --g ${myInput.groupFile.unixPath} --sc ${myInput.sampleColorFile.unixPath} --solution ${myInput.solutionFile.map(_.unixPath).toMyString}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "produce_meta_color.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def treatVenn(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "treat_venn_calculate.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "treat_venn_plot.R").unixPath}  --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "treat_venn_calculate_only_two_group.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "treat_venn_plot_only_two_group.R").unixPath} --base ${Tool.smallBaseFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))

  }

  def csVenn(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_self_venn_calculate.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_self_venn_plot.R").unixPath} --config ${myInput.configFile.unixPath} --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_self_venn_calculate_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_self_venn_plot_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath} --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_upload_venn_calculate.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_upload_venn_plot.R").unixPath} --config ${myInput.configFile.unixPath}  --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_upload_venn_calculate_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_upload_venn_plot_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath} --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_confounder_venn_calculate.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_confounder_venn_plot.R").unixPath} --config ${myInput.configFile.unixPath} --base ${Tool.smallBaseFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_confounder_venn_calculate_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "cs_confounder_venn_plot_only_two_group.R").unixPath} --config ${myInput.configFile.unixPath} --base ${Tool.smallBaseFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))

  }


  def stepQC(commandExecutor: CommandExecutor)(implicit myInput: MyInputFile, myResultDir: MyResultDir,
                                               myWorkspaceDir: MyWorkspaceDir) = {

    val hasQc = myInput.groupFile.csvLines.selectOneColumn("classnote").contains("QC")
    if (hasQc) {
      commandExecutor.exec { () =>
        Tool.stepQcin(myWorkspaceDir.qcDir)
      }.map { () =>
        Tool.stepQcinCopy
      }.exec { () =>
        stepQc1(myWorkspaceDir.qcInDir.dir01)
      }.map { () =>
        Tool.stepQc1Copy
      }.exec { () =>
        Tool.stepQc2(myWorkspaceDir.qcInDir.dir02)
      }.map { () =>
        Tool.stepQc2Copy
      }
    } else {
      commandExecutor.exec { () =>
        Tool.stepQcNoQcSampleIn(myWorkspaceDir.qcDir)
      }.map { () =>
        Tool.stepQcinCopy
      }.exec { () =>
        Tool.stepQcNoQcSample01(myWorkspaceDir.qcInDir.dir01)
      }.map { () =>
        Tool.stepQc1Copy
      }
    }
    commandExecutor

  }

  def stepQc1(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_calculate.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "qc.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath} --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_plot.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_plot_with_label.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))

  }

  def stepQc2(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "qc_heatmap.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath} --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "qc_chord.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath} --sc ${myInput.sampleColorFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))

  }

  def stepQcin(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |#Rscript ${new File(Utils.rPath, "qc_rsd.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "super_class_count.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "super_class_count_pie_plot.R").unixPath} --i ${myInput.qcDataFile.unixPath} --g ${myInput.groupFile.unixPath}   --mc ${myInput.metaColorFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def stepQcNoQcSampleIn(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "super_class_count.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "super_class_count_pie_plot.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}   --mc ${myInput.metaColorFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def stepQcNoQcSample01(workspaceDir: File)(implicit myInput: MyInputFile) = {
    val command =
      s"""
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "qc_no_qc_sample.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath} --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_calculate.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_plot.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath}
         |${"Rscript".condaPath()} ${new File(Utils.rPath, "pca_with_qc_plot_with_label.R").unixPath} --i ${myInput.dataFile.unixPath} --g ${myInput.groupFile.unixPath}   --sc ${myInput.sampleColorFile.unixPath}
           """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def getMyResultDir(resultDir: File) = {
    val preDir = createAndReturnDir(resultDir, "Preprocessed_Data")
    val treatDir = createAndReturnDir(resultDir, "Treatment")
    val inDirTreat = getInDirTreat(treatDir)
    val qcDir = returnDir(resultDir, "Quality_Control")
    val qcInDir = getQcInResultDir(qcDir)
    MyResultDir(preDir, treatDir, inDirTreat, qcDir, qcInDir)
  }

  def getMyWorkspaceDir(dir: File) = {
    val qcDir = Tool.createAndReturnDir(dir, "QC")
    val qcInDir = getInDir02(qcDir)
    val treatDir = Tool.createAndReturnDir(dir, "treat")
    val inDirTreat = getInDirTreat(treatDir)
    MyWorkspaceDir(qcDir, qcInDir, treatDir, inDirTreat)
  }

  def createAndReturnDir(dir: File, subDirName: String) = {
    new File(dir, subDirName).createDirectoryWhenNoExist
  }

  def returnDir(dir: File, subDirName: String) = {
    val subDir = new File(dir, subDirName)
    subDir
  }

  def getInDir02(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "01")
    val dir02 = createAndReturnDir(workspaceDir, "02")
    InDir02(dir01, dir02)
  }

  def getCvPDir(dir:File)={
    val cvDir=createAndReturnDir(dir,"cv")
    CvPDir(self = dir, cvDir = cvDir)
  }

  def getInDirMg(workspaceDir: File) = {
    val gbDir = createAndReturnDir(workspaceDir, "gb")
    val gbCvPDir=getCvPDir(gbDir)
    val lrDir = createAndReturnDir(workspaceDir, "lr")
    val lrCvPDir=getCvPDir(lrDir)
    val rfDIr = createAndReturnDir(workspaceDir, "rf")
    val rfCvPDir=getCvPDir(rfDIr)
    val rocDir = createAndReturnDir(workspaceDir, "roc")
    InDirMg(gbCvPDir, lrCvPDir, rfCvPDir, rocDir)
  }

  def getPathwayInDir(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "01")
    val dir02 = createAndReturnDir(workspaceDir, "02")
    val dir03 = createAndReturnDir(workspaceDir, "03")
    InDir03(dir01, dir02, dir03)
  }

  def getInDir04(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "01")
    val dir02 = createAndReturnDir(workspaceDir, "02")
    val dir03 = createAndReturnDir(workspaceDir, "03")
    val dir04 = createAndReturnDir(workspaceDir, "04")
    InDir04(dir01, dir02, dir03, dir04)
  }

  def getMgDir(dir: File) = {
    val mgDir = createAndReturnDir(dir, "mg")
    val inDirMg = getInDirMg(mgDir)
    MgDir(self = dir, mgDir = inDirMg)
  }

  def getInDirDignose(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "01")
    val rfDir = getMgDir(dir01)
    val dir02 = createAndReturnDir(workspaceDir, "02")
    val svmDir = getMgDir(dir02)
    val dir03 = createAndReturnDir(workspaceDir, "03")
    val borutaDir = getMgDir(dir03)
    InDirDignose(rfDir, svmDir, borutaDir,workspaceDir)
  }

  def getInDir01(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "01")
    InDir01(dir01)
  }

  def getQcInResultDir(workspaceDir: File) = {
    val dir01 = returnDir(workspaceDir, "01_PC1_with_All_Samples")
    val dir02 = returnDir(workspaceDir, "02_QC_Correlation_Pearson")
    InDir02(dir01, dir02)
  }

  def getInDirTreat(workspaceDir: File) = {
    val csDir = returnDir(workspaceDir, "Correlation_Summary")
    val smsDir = returnDir(workspaceDir, "Sig_Met_Summary")
    InDirTreat(csDir, smsDir)
  }

  def getInResultDir01(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "Metabolite_Class_Statistics")
    InDir01(dir01)
  }

  def getInResultDir02(workspaceDir: File) = {
    val dir01 = createAndReturnDir(workspaceDir, "Uni_Group")
    val dir02 = createAndReturnDir(workspaceDir, "All_Groups")
    InDir02(dir01, dir02)
  }

  def getResultMgDir(dir: File) = {
    val mgDir = returnDir(dir, "Diagnose_Model_Generation")
    val inMgDir = getInResultDirMg(mgDir)
    MgDir(self = dir, mgDir = inMgDir)
  }

  def getResultDiagnoseInDir(workspaceDir: File) = {
    val dir01 = returnDir(workspaceDir, "01_Random_Forest")
    val rfDir = getResultMgDir(dir01)
    val dir02 = returnDir(workspaceDir, "02_Support_Vector_Machine")
    val svmDir = getResultMgDir(dir02)
    val dir03 = returnDir(workspaceDir, "03_Boruta")
    val borutaDir = getResultMgDir(dir03)
    InDirDignose(rfDir, svmDir, borutaDir,workspaceDir)
  }

  def getResultCvPDir(dir:File)={
    val cvDir=createAndReturnDir(dir,"Cross-Validation-Results")
    CvPDir(self = dir, cvDir = cvDir)
  }

  def getInResultDirMg(workspaceDir: File) = {
    val gbDir = returnDir(workspaceDir, "Gradient_Boosting")
    val gbCvPDir=getResultCvPDir(gbDir)
    val lrDir = returnDir(workspaceDir, "Logistic_Regression")
    val lrCvPDir=getResultCvPDir(lrDir)
    val rfDir = returnDir(workspaceDir, "Random_Forest")
    val rfCvPDir=getResultCvPDir(rfDir)
    val rocDir = returnDir(workspaceDir, "Single_Met_ROC")
    InDirMg(gbCvPDir, lrCvPDir, rfCvPDir, rocDir)
  }

  def getResultPathwayInDir(workspaceDir: File) = {
    val dir01 = returnDir(workspaceDir, "Pathway_Analysis")
    val dir02 = returnDir(workspaceDir, "iPath3")
    val dir03 = returnDir(workspaceDir, "Enrichment_Analysis")
    InDir03(dir01, dir02, dir03)
  }

  def getResultCorInDir(workspaceDir: File) = {
    val dir01 = returnDir(workspaceDir, "Spearman")
    val dir02 = returnDir(workspaceDir, "Spearman_Partial")
    InDir02(dir01, dir02)
  }

  def getMyInWorkspaceDir(workspaceDir: File) = {
    val dir0 = createAndReturnDir(workspaceDir, "00")
    val basicDir = createAndReturnDir(workspaceDir, "basic")
    val basicInDir = getInDir01(basicDir)
    val pcaDir = createAndReturnDir(workspaceDir, "pca")
    val pcaInDir = getInDir02(pcaDir)
    val plsdaDir = createAndReturnDir(workspaceDir, "plsda")
    val oplsdaDir = createAndReturnDir(workspaceDir, "oplsda")
    val uniDir = createAndReturnDir(workspaceDir, "uni")
    val potentialDir = createAndReturnDir(workspaceDir, "potential")
    val corDir = createAndReturnDir(workspaceDir, "cor")
    val corInDir = getInDir02(corDir)
    val pathwayDir = createAndReturnDir(workspaceDir, "pathway")
    val pathwayInDir = getPathwayInDir(pathwayDir)
    val diagnoseDir = createAndReturnDir(workspaceDir, "diagnose")
    val diagnoseInDir = getInDirDignose(diagnoseDir)
    MyInWorkspaceDir(dir0, basicDir, basicInDir, pcaDir, pcaInDir, plsdaDir, oplsdaDir, uniDir, potentialDir, corDir,
      corInDir, pathwayDir, pathwayInDir, diagnoseDir, diagnoseInDir)
  }

  def getMyInResultDir(resultDir: File, cpName: String, configData: ConfigData) = {
    val basicDir = createAndReturnDir(resultDir, "01_Basic_Statistics")
    val basicInDir = getInResultDir01(basicDir)
    val pcaDir = createAndReturnDir(resultDir, "02_PCA")
    val pcaInDir = getInResultDir02(pcaDir)
    val plsdaDir = createAndReturnDir(resultDir, "03_PLS_DA")
    val oplsdaDir = returnDir(resultDir, "04_OPLS_DA")
    val isMulti = Tool.isMulti(cpName)
    var i = 4
    val uniDir = if (isMulti) {
      createAndReturnDir(resultDir, s"0${i}_Univariate_Analysis")
    }
    else {
      i += 1
      createAndReturnDir(resultDir, s"0${i}_Univariate_Analysis")
    }

    i += 1
    val potentialDir = createAndReturnDir(resultDir, s"0${i}_Potential_Biomarkers")

    i += 1
    val pathwayDir = returnDir(resultDir, s"0${i}_Pathway_Analysis")
    val pathwayInDir = getResultPathwayInDir(pathwayDir)
    if (configData.pathway.isPathwayExec == "T") {
      i += 1
    }

    val corDir = returnDir(resultDir, s"0${i}_Correlation_Analysis")
    val corInDir = getResultCorInDir(corDir)

    i += 1
    val diagnoseDir = returnDir(resultDir, s"0${i}_Diagnose")
    val diagnoseInDir = getResultDiagnoseInDir(diagnoseDir)
    if (configData.diagnoseIsExec == "yes") {
      i += 1
    }

    MyInResultDir(basicDir, basicInDir, pcaDir, pcaInDir, plsdaDir, oplsdaDir, uniDir, potentialDir, corDir, corInDir,
      pathwayDir, pathwayInDir, diagnoseDir, diagnoseInDir)
  }

  def isValidFileName(name: String) = {
    val suffixs = List(".pdf", ".csv", ".svg", ".json", ".html", ".js", ".xlsx")
    suffixs.exists(x => name.endsWith(x)) && (!name.startsWith("Rplots"))
  }

  val fileNameFilter = new FilenameFilter {
    override def accept(dir: File, name: String): Boolean = {
      isValidFileName(name)
    }

  }

  val fileFilter = new FileFilter {
    override def accept(file: File): Boolean = {
      file.isDirectory
    }
  }

  def stepPreCopy(implicit workspaceDir: File, myResultDir: MyResultDir) = {
    fileCopy(workspaceDir, myResultDir.preDir)
  }

  def treatVennCopy(implicit workspaceDir: File, myResultDir: MyResultDir) = {
    fileCopy(workspaceDir, myResultDir.inDirTreat.smsDir)
  }

  def csVennCopy(implicit workspaceDir: File, myResultDir: MyResultDir) = {
    sameDirCopyWithCurrent(workspaceDir, myResultDir.inDirTreat.csDir)
  }

  def stepQc1Copy(implicit myWorkspaceDir: MyWorkspaceDir, myResultDir: MyResultDir) = {
    Tool.fileCopy(myWorkspaceDir.qcInDir.dir01, myResultDir.qcInDir.dir01)
  }

  def stepQc2Copy(implicit myWorkspaceDir: MyWorkspaceDir, myResultDir: MyResultDir) = {
    Tool.fileCopy(myWorkspaceDir.qcInDir.dir02, myResultDir.qcInDir.dir02)
  }

  def stepBasic1Copy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    Tool.fileCopy(myWorkspaceDir.basicInDir.dir01, myResultDir.basicInDir.dir01)

  }

  def stepPca1Copy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    Tool.fileCopy(myWorkspaceDir.pcaInDir.dir01, myResultDir.pcaInDir.dir01)

  }

  def stepPca2Copy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    sameDirCopyWithCurrent(myWorkspaceDir.pcaInDir.dir02, myResultDir.pcaInDir.dir02)
  }

  def stepQcinCopy(implicit myWorkspaceDir: MyWorkspaceDir, myResultDir: MyResultDir) = {
    Tool.fileCopy(myWorkspaceDir.qcDir, myResultDir.qcDir)
  }

  def stepBasicinCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    Tool.fileCopy(myWorkspaceDir.basicDir, myResultDir.basicDir)
  }

  def stepPlsdainCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    fileCopy(myWorkspaceDir.plsdaDir, myResultDir.plsdaDir)
  }

  def stepOplsdainCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    sameDirCopyWithCurrent(myWorkspaceDir.oplsdaDir, myResultDir.oplsdaDir)
  }

  def stepPotentialinCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    val files = List(new File(myWorkspaceDir.potentialDir, "AllMet_Tests_Joined.csv"),
      new File(myWorkspaceDir.potentialDir, "Markers.csv"))
    dyeColors(files)
    fileCopy(myWorkspaceDir.potentialDir, myResultDir.potentialDir)
  }

  def stepPotentialinMultiCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    val files = List(new File(myWorkspaceDir.potentialDir, "AllMet_Test.csv"),
      new File(myWorkspaceDir.potentialDir, "Markers.csv"))
    dyeColors(files)
    fileCopy(myWorkspaceDir.potentialDir, myResultDir.potentialDir)
  }

  def dyeColors(files: List[File]) = {
    files.foreach { file =>
      dyeColor(file)
    }
  }

  def dyeColor(file: File) = {
    val outFile = new File(file.getParent, s"${file.namePrefix}.xlsx")
    val outputWorkbook = new XSSFWorkbook()
    val outputSheet = outputWorkbook.createSheet("Sheet1")
    val lines = file.csvLines
    val xlsxStyle = new XlsxStyle(outputWorkbook)
    val headers = lines(0)
    lines.zipWithIndex.foreach { case (columns, i) =>
      val outputEachRow = outputSheet.createRow(i)
      columns.zipWithIndex.foreach { case (column, j) =>
        val header = headers(j)
        val cell = outputEachRow.createCell(j)
        cell.setCellValue(column)
        if (i > 0 && column.isDouble) {
          cell.setCellValue(column.toDouble)
          val color = Tool.getColor(header, column)
          val style = color match {
            case "orange" => xlsxStyle.orangeStyle
            case "red" => xlsxStyle.redStyle
            case "darkRed" => xlsxStyle.darkRedStyle
            case "cyan" => xlsxStyle.cyanStyle
            case "blue" => xlsxStyle.blueStyle
            case _ => xlsxStyle.emptyStyle
          }
          cell.setCellStyle(style)
        }
      }
    }
    val fileOutputStream = new FileOutputStream(outFile)
    outputWorkbook.write(fileOutputStream)
    fileOutputStream.close()
    outputWorkbook.close()
  }

  def stepUniinCopy(implicit myWorkspaceDir: MyInWorkspaceDir, myResultDir: MyInResultDir) = {
    fileCopy(myWorkspaceDir.uniDir, myResultDir.uniDir)
  }

  def sameDirCopy(sourceDir: File, targetDir: File) = {
    sourceDir.listFiles(fileFilter).foreach {
      dir =>
        val dirName = dir.getName
        val newDir = new File(targetDir, dirName).createDirectoryWhenNoExist
        dir.listFiles(fileNameFilter).foreach {
          file =>
            FileUtils.copyFileToDirectory(file, newDir)
        }
    }
  }

  def sameDirCopyRecu(sourceDir: File, targetDir: File) = {

    def loop(file: File): Unit = {
      for (file <- file.listFiles()) {
        if (file.isDirectory) {
          loop(file)
        } else {
          if (isValidFileName(file.getName)) {
            val filePath = file.getAbsolutePath
            val sourcePath = sourceDir.getAbsolutePath
            val targetFile = new File(targetDir, filePath.replace(sourcePath, ""))
            FileUtils.copyFile(file, targetFile)
          }

        }
      }
    }

    loop(sourceDir)

  }

  def sameDirCopyWithCurrent(sourceDir: File, targetDir: File) = {
    fileCopy(sourceDir, targetDir)
    sameDirCopyRecu(sourceDir, targetDir)
  }

  def fileCopy(sourceDir: File, targetDir: File) = {
    sourceDir.listFiles(fileNameFilter).foreach {
      file =>
        FileUtils.copyFileToDirectory(file, targetDir)
    }
  }

  def getColor(header: String, column: String) = {
    if (header == "Uni_P") {
      column.toDouble match {
        case x if x < 0.05 && x >= 0.01 =>
          "orange"
        case x if x < 0.01 => "red"
        case _ => ""
      }
    } else if (header == "Uni_FDR") {
      column.toDouble match {
        case x if x < 0.05 =>
          "darkRed"
        case _ => ""
      }
    } else if (header == "OPLSDA_VIP") {
      column.toDouble match {
        case x if x > 1 =>
          "orange"
        case _ => ""
      }
    } else if (header == "log2FC") {
      column.toDouble match {
        case x if x > 1 && x <= 2 =>
          "orange"
        case x if x > 2 =>
          "red"
        case x if x < -1 && x >= -2 =>
          "cyan"
        case x if x < -2 =>
          "blue"
        case _ => ""
      }
    } else ""
  }

  def cleanName(name: String) = {
    var newName = Tool.cleanSpecialChr(name.trim)
    val symbols = List("_", "-", "：", ":", "（", "(", ")", "）", "/", "—")
    symbols.foreach {
      symbol =>
        newName = newName.replace(symbol, " ")
    }
    newName = newName.replace("?", "").replaceAll("\\s+", " ")
    newName.toLowerCase
  }

  lazy val letterMap = {
    val letterFile = new File(Utils.dataDir, "replace_info.txt")
    letterFile.txtLines.map { columns =>
      (columns(0) -> columns(1))
    }.toMap
  }

  def cleanSpecialChr(name: String) = {
    var newName = name
    letterMap.foreach {
      case (letter, text) =>
        newName = newName.replace(letter, text)
    }
    newName
  }

  def isMulti(cpName: String) = {
    val cpNames = cpName.split("_vs_")
    cpNames.size > 2
  }

  def getSolutionFile(configData: ConfigData) = {
    configData.colorSolution.map { solution =>
      new File(Utils.dataDir, s"color_solution/color_solution_${solution}.txt")
    }
  }

  def correctConfigMap(map: Map[String, String]) = {
    val map1 = if (map("diffMethod.fdr").toDouble >= 1) {
      Map("diffMethod.fdr" -> "1")
    } else Map[String, String]()
    val map2 = if (map("diffMethod.kwFdr").toDouble >= 1) {
      Map("diffMethod.kwFdr" -> "1")
    } else Map[String, String]()
    val map3 = if (map("cor.fdr").toDouble >= 1) {
      Map("cor.fdr" -> "1")
    } else Map[String, String]()
    map ++ map1 ++ map2 ++ map3
  }


  def trimMet(file: File) = {
    (file.csvLines.head :: file.csvLines.drop(1)).map { columns =>
      columns(0).trim :: columns.drop(1)
    }.toFile(file)
  }

  def getMyInput(myTmpDir: MyDataDir, workspaceDir: File, configData: ConfigData) = {
    val rawDataFile = new File(workspaceDir, "00_AllMet_Raw.csv")
    trimMet(myTmpDir.dataFile)
    FileUtils.moveFile(myTmpDir.dataFile, rawDataFile)
    val groupFile = new File(workspaceDir, "Class_Info.csv")
    FileTool.groupFileDeal(myTmpDir.groupFile, groupFile)
    val compareFile = new File(workspaceDir, "Treatment.csv")
    FileUtils.moveFile(myTmpDir.compareFile, compareFile)
    val sampleColorFile = new File(workspaceDir, "Class_Color.csv")
    FileTool.sampleColorFileDeal(myTmpDir.sampleColorFile, sampleColorFile)
    val workspaceCorDir = Tool.returnDir(workspaceDir, "cor_extra_data")
    FileUtils.moveDirectory(myTmpDir.corDir, workspaceCorDir)
    val workspaceConfounderFile = new File(workspaceDir, "confounder.csv")
    myTmpDir.confounderFile.foreach { confounderFile =>
      FileUtils.moveFile(confounderFile, workspaceConfounderFile)
    }
    val dataFile = new File(workspaceDir, "04_AllMet.csv")
    val metaColorFile = new File(workspaceDir, "meta_color.txt")
    val configFile = Tool.produceConfigFile(configData, workspaceDir)
    val solutionFile = Tool.getSolutionFile(configData)
    val qcDataFile = dataFile
    MyInputFile(rawDataFile, dataFile, qcDataFile, groupFile, sampleColorFile, compareFile, workspaceCorDir,
      workspaceConfounderFile, metaColorFile, configFile, solutionFile)
  }

  def getMyInput(workspaceDir: File, configData: ConfigData) = {
    val rawDataFile = new File(workspaceDir, "00_AllMet_Raw.csv")
    val groupFile = new File(workspaceDir, "Class_Info.csv")
    val compareFile = new File(workspaceDir, "Treatment.csv")
    val sampleColorFile = new File(workspaceDir, "Class_Color.csv")
    val workspaceCorDir = Tool.returnDir(workspaceDir, "cor_extra_data")
    val workspaceConfounderFile = new File(workspaceDir, "confounder.csv")
    val dataFile = new File(workspaceDir, "04_AllMet.csv")
    val metaColorFile = new File(workspaceDir, "meta_color.txt")
    val configFile = new File(workspaceDir, "config.txt")
    val solutionFile = Tool.getSolutionFile(configData)
    val qcDataFile =  dataFile
    MyInputFile(rawDataFile, dataFile, qcDataFile, groupFile, sampleColorFile, compareFile, workspaceCorDir,
      workspaceConfounderFile, metaColorFile, configFile, solutionFile)
  }

  def getMyInputFromOther(otherDir: File, workspaceDir: File, configData: ConfigData) = {
    val rawDataFile = Tool.copyAndReturnFile(otherDir, workspaceDir, "00_AllMet_Raw.csv")
    val groupFile = Tool.copyAndReturnFile(otherDir, workspaceDir, "Class_Info.csv")
    val compareFile = Tool.copyAndReturnFile(otherDir, workspaceDir, "Treatment.csv")
    val sampleColorFile = Tool.copyAndReturnFile(otherDir, workspaceDir, "Class_Color.csv")
    val workspaceCorDir = Tool.copyAndReturnDir(otherDir, workspaceDir, "cor_extra_data")
    val workspaceConfounderFile = Tool.copyAndReturnFile(otherDir, workspaceDir, "confounder.csv")
    val configFile = Tool.produceConfigFile(configData, workspaceDir)
    val dataFile = new File(workspaceDir, "04_AllMet.csv")
    val metaColorFile = new File(workspaceDir, "meta_color.txt")
    val otherDataDir = new File(otherDir.getParentFile, "data")
    FileUtils.copyDirectoryToDirectory(otherDataDir, workspaceDir.getParentFile)
    val solutionFile = Tool.getSolutionFile(configData)
    val qcDataFile =  dataFile
    MyInputFile(rawDataFile, dataFile, qcDataFile, groupFile, sampleColorFile, compareFile, workspaceCorDir, workspaceConfounderFile,
      metaColorFile, configFile, solutionFile)
  }

  def copyAndReturnFile(srcDir: File, destDir: File, fileName: String) = {
    val destFile = new File(destDir, fileName)
    val srcFile = new File(srcDir, fileName)
    if (srcFile.exists()) {
      FileUtils.copyFile(srcFile, destFile)
    }
    destFile
  }

  def copyAndReturnDir(srcDir: File, destDir: File, dirName: String) = {
    val destInDir = new File(destDir, dirName)
    val srcInDir = new File(srcDir, dirName)
    FileUtils.copyDirectory(srcInDir, destInDir)
    destInDir
  }

  def getMyInInput(columns: List[String], configData: ConfigData, myInput: MyInputFile, workspaceDir: File,
                   inWorkspaceDir: File) = {
    val trueSampleFile = new File(inWorkspaceDir, "true_SampleInfo.csv")
    val trueSampleColorFile = new File(inWorkspaceDir, "Class_Color.csv")
    val metaColorFile = new File(inWorkspaceDir, "meta_color.txt")
    val configFile = Tool.produceInConfigFile(configData, columns, inWorkspaceDir)
    val corDir = Tool.createAndReturnDir(inWorkspaceDir, "cor_extra_data")
    FileUtils.copyDirectory(myInput.corDir, corDir)
    val confounderFile = new File(inWorkspaceDir, "confounder.csv")
    if (myInput.confounderFile.exists()) {
      FileUtils.copyFile(myInput.confounderFile, confounderFile)
    }
    val inDataFile = Tool.getDataFile(workspaceDir, inWorkspaceDir, configData)
    val scaleDataFile = new File(inWorkspaceDir, "scale_data.csv")
    val mustScaleFile = new File(inWorkspaceDir, "must_scale_data.csv")
    MyInInput(trueSampleFile, trueSampleColorFile, configFile, corDir, confounderFile, inDataFile,
      metaColorFile, scaleDataFile, mustScaleFile)
  }

  def getUserMissionDir(implicit request: RequestHeader) = {
    val userIdDir = getUserIdDir
    new File(userIdDir, "mission")
  }

  def getUserMissionDir(userId: Int) = {
    val userIdDir = getUserIdDir(userId)
    new File(userIdDir, "mission")
  }

  def getMissionIdDir(missionId: Int)(implicit request: RequestHeader) = {
    val userMissionFile = getUserMissionDir
    new File(userMissionFile, missionId.toString)
  }

  def getMissionIdDir(mission: MissionRow) = {
    val userMissionFile = getUserMissionDir(mission.userId)
    new File(userMissionFile, mission.id.toString)
  }

  def getUserIdDir(userId: Int) = {
    new File(Utils.userDir, userId.toString)
  }

  def getConfigDir(implicit request: RequestHeader) = {
    val userIdDir = getUserIdDir
    new File(userIdDir, "config")
  }

  def getConfigFile(id: Int)(implicit request: RequestHeader) = {
    val dir = getConfigDir
    new File(dir, s"${
      id
    }.config")
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Utils.userDir, userId.toString)
  }

  def getMissionWorkspaceDirById(missionId: Int)(implicit request: RequestHeader) = {
    val missionIdDir = getMissionIdDir(missionId)
    new File(missionIdDir, "workspace")
  }

  def getMissionWorkspaceDirById(mission: MissionRow) = {
    val missionIdDir = getMissionIdDir(mission)
    new File(missionIdDir, "workspace")
  }

  def getUserResultDir(missionId: Int)(implicit request: RequestHeader) = {
    val missionIdDir = getMissionIdDir(missionId)
    new File(missionIdDir, "result")
  }

  def getUserResultDir(mission: MissionRow) = {
    val missionIdDir = getMissionIdDir(mission)
    new File(missionIdDir, "result")
  }

  def getSourceDir(missionId: Int)(implicit request: RequestHeader): File = {
    val missionIdDir = getMissionIdDir(missionId)
    getSourceDir(missionIdDir)
  }

  val reportDirName = "report.files"

  def getSourceDir(missionIdDir: File): File = {
    val reportDir = getReportDir(missionIdDir)
    new File(reportDir, s"sources")
  }

  def getReportDir(missionIdDir: File): File = {
    new File(missionIdDir, s"result/${
      reportDirName
    }")
  }

  def getPreDataDir(missionId: Int)(implicit request: RequestHeader) = {
    val resultDir = getUserResultDir(missionId)
    new File(resultDir, "Preprocessed_Data")
  }

  def getTreatDir(missionId: Int)(implicit request: RequestHeader) = {
    val resultDir = getUserResultDir(missionId)
    new File(resultDir, "Treatment")
  }


  def getUserId(implicit request: RequestHeader) = {
    request.session.get("id").get.toInt
  }

  val availCpu = Runtime.getRuntime.availableProcessors() - 1

  def generateMissionName = {
    (new DateTime).toString("yyyy_MM_dd_HH_mm_ss")
  }


}
